package com.gaga.console.core.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSON;
import com.gaga.common.constant.BvConstants;
import com.gaga.common.enums.*;
import com.gaga.common.utils.TemplateReplacer;
import com.gaga.console.base.mybatisplus.LambdaQueryWrapperExt;
import com.gaga.console.base.utils.MyDecimalUtil;
import com.gaga.console.core.entity.BvScriptItem;
import com.gaga.console.core.entity.dto.*;
import com.gaga.console.core.entity.vo.TextToSpeechVo;
import com.gaga.console.core.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;

/**
 * @author liujia
 * @version 1.0
 * @date 2025/5/1-13:06
 */
@Slf4j
@Service
public class AudioGenQueueServiceImpl implements AudioGenQueueService {

    @Autowired
    private BvModelService bvModelService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private BvAudioPlayService bvAudioPlayService;

    @Autowired
    private BvConfigService bvConfigService;

    private final ExecutorService genExecutor = ThreadUtil.newSingleExecutor();

    /**
     * 是否正在生成
     */
    private volatile boolean isGening = false;

    // 添加队列大小限制常量
    private static final int MAX_QUEUE_SIZE = 20;
    // 主音频队列最大限制
    private static final int MAX_MAIN_AUDIO_QUEUE_SIZE = 5;

    private final ConcurrentLinkedDeque<AudioGenDto> genQueue = new ConcurrentLinkedDeque<>();

    @Autowired
    private AudioPlayQueueService audioPlayQueueService;

    @Autowired
    private BvScriptItemService bvScriptItemService;

    @Autowired
    private BvConfigServiceImpl bvConfigServiceImpl;

    @Override
    public void addToQueue(AudioGenDto audioDto) {
        // 对主音频进行严格控制，确保不会过多生成
        if ("mainAudio".equals(audioDto.getSource())) {
            // 检查当前主音频队列大小，超过限制则不添加
            Integer mainAudioQueueSize = audioPlayQueueService.getQueueSizeByScriptType(ScriptType.MAIN_AUDIO);
            if (mainAudioQueueSize >= MAX_MAIN_AUDIO_QUEUE_SIZE) {
                log.info("主音频队列已达到上限 {}，跳过添加此主音频任务", MAX_MAIN_AUDIO_QUEUE_SIZE);
                return;
            }
        }

        bvAudioPlayService.fixQueneSizeSleep(audioDto.getSource());
        genQueue.addLast(audioDto);
        tryGenAudio();
    }

    @Override
    public void insertFirstToQueue(AudioGenDto audioDto) {
        // 对于非主音频任务，不需要严格控制
        if (!"mainAudio".equals(audioDto.getSource())) {
            bvAudioPlayService.fixQueneSizeSleep(audioDto.getSource());
            genQueue.addFirst(audioDto);
            tryGenAudio();
            return;
        }
        genQueue.addFirst(audioDto);
        tryGenAudio();
    }

    @Override
    public void stopGen() {
        log.info("停止音频生成，清理所有资源");

        // 清理队列
        int queueSize = genQueue.size();
        genQueue.clear();
        log.info("清理了{}个待生成音频请求", queueSize);

        // 重置状态
        isGening = false;

        // 强制进行垃圾回收
        log.info("音频生成停止完成，所有资源已释放");
    }

    @Override
    public Integer getQueueSize() {
        return genQueue.size();
    }

    private synchronized void tryGenAudio() {

        log.error("==2=gen isGening:{}, genQueueSize {}", isGening, genQueue.size());

        //todo 需要控制死循环
        while (LiveRoomStatusType.pause.getCode().equals(bvAudioPlayService.getLiveRoomStatus())) {
            ThreadUtil.sleep(1000);
        }

        // 检查当前是否有锚点正在播放以及锚点队列是否为空
        if (!isGening && !genQueue.isEmpty()) {
            // 设置锚点播放状态为正在播放
            isGening = true;
            // 提交任务以处理锚点队列
            genExecutor.submit(this::commonTextToSpeech);
        }
    }

    /**
     * 生成
     *
     * @return
     */
    public void commonTextToSpeech() {
        TextToSpeechFrontDto dto = new TextToSpeechFrontDto();
        try {
            ThreadUtil.sleep(1000);

            AudioGenDto audioGenDto = genQueue.poll();
            log.error("==3=commonTextToSpeech genQueueSize {}", genQueue.size());
            log.error("==31=commonTextToSpeech audioGenDto {}", JSON.toJSONString(audioGenDto));

            if (audioGenDto == null) {
                isGening = false;
                return;
            }

            try {
                ConfigDto configDto = bvConfigService.getConfig();
                Integer maxCharLength = configDto.getAudioSetting().getAudioGen().getMaxCharLength();

                String randomSelectText = TemplateReplacer.randomSelectText(audioGenDto.getText());
                if (randomSelectText.length() > maxCharLength) {
                    log.warn("文本长度超过限制，跳过生成: {}", randomSelectText);
                    isGening = false;
                    tryGenAudio(); // 尝试处理下一个
                    return;
                }
                if (audioGenDto.getSource().equals("mainAudio") &&
                        ScriptItemFileType.FOLDER.getCode().equals(audioGenDto.getScriptItem().getItemFileType())) {
                    fileTypeFolderAudioPlay(audioGenDto);
                    isGening = false;
                    tryGenAudio(); // 尝试处理下一个
                    return;
                }
                log.error("==32=commonTextToSpeech audioGenDto");

                BvScriptItem scriptItem = audioGenDto.getScriptItem();
                PlayDto playDto = audioGenDto.getPlayDto();
                // 创建基础DTO
                dto.setText(audioGenDto.getText());

                log.error("==33=commonTextToSpeech TextToSpeechFrontDto {}", JSON.toJSONString(dto));

                // 1. 确定播放者类型
                PlayerType playerType = determinePlayerType(audioGenDto.getSource(), scriptItem, configDto, playDto);
                dto.setPlayerType(playerType);

                log.error("==34=commonTextToSpeech playerType {}", playerType);

                if ("mainAudio".equals(audioGenDto.getSource())) {
                    // 2. 确定并切换模型
                    String targetModelName = determineModelName(playerType, configDto);
                    String tempPath = audioGenDto.getGenerateAudioPath() + targetModelName + File.separator + scriptItem.getItemName() + File.separator + System.currentTimeMillis() + BvConstants.WAV_FORMAT;
                    dto.setGenerateAudioPath(tempPath);
                } else {
                    dto.setGenerateAudioPath(audioGenDto.getGenerateAudioPath());
                }

                // 3. 设置生成路径
                dto.setChannelId(configDto.getSseChannelId());

                // 5. 设置智能回复参数
                Boolean smartPolish = configDto.getMainAudioSetting().getSmartReply().getOpen();

                if (audioGenDto.getSource().equals("generate") && playDto != null) {
                    String speaker = getSpeaker(playDto, configDto);
                    dto.setPlayerType(PlayerType.getPlayerTypeByCode(speaker));
                    dto.setUserName(playDto.getUserName());
                    dto.setScriptType(playDto.getScriptType());

                    switch (dto.getScriptType()) {
                        case KEYWORD:
                            smartPolish = configDto.getKeywordSetting().getSmartReply().getOpen();
                            dto.setRepeatProblem(configDto.getKeywordSetting().getRepeatProblem());
                            dto.setProblemText(playDto.getProblemText());
                            break;
                        case USER_ENTER:
                            smartPolish = configDto.getUserEnterSetting().getSmartReply().getOpen();
                            break;
                        case SMART_REPLY:
                            dto.setSmartQA(configDto.getSmartReplySetting().getOpen());
                            dto.setProblemText(playDto.getText());
                            dto.setAnchorName(configDto.getSmartReplySetting().getAnchorName());
                            dto.setUserCallName(configDto.getSmartReplySetting().getUserCallName());
                            dto.setRepeatProblem(configDto.getSmartReplySetting().getRepeatProblem());
                            break;
                        case INSERT_AUDIO:
                            dto.setSmartPolish(false);
                        default:
                            break;
                    }
                } else {
                    dto.setScriptType(ScriptType.MAIN_AUDIO);
                }

                dto.setSmartPolish(smartPolish);
                dto.setBlockWords(configDto.getAiSetting().getBlockWords());
                dto.setLiveRoomDesc(configDto.getAiSetting().getLiveRoomDesc());
                dto.setModelId(configDto.getAiSetting().getModelId());
                dto.setToken(configDto.getAiSetting().getToken());

                log.error("==36=commonTextToSpeech TextToSpeechFrontDto {}", JSON.toJSONString(dto));

                // 6. 执行语音合成
                TextToSpeechVo result = bvModelService.textToSpeech(dto);
                log.error("==37=commonTextToSpeech TextToSpeechVo {}", JSON.toJSONString(result));

                if (audioGenDto.getSource().equals("mainAudio")) {
                    boolean broadTime = dto.getText().contains("[时间]");
                    mainAudioAfterHandler(audioGenDto, result, dto.getPlayerType(), broadTime);
                } else if (audioGenDto.getSource().equals("generate")) {
                    generateAudioAfterHandler(audioGenDto, result, dto.getPlayerType());
                }
                log.error("==38=commonTextToSpeech");

            } catch (Exception e) {
                log.error("处理音频生成请求失败: " + e.getMessage(), e);
            } finally {
                // 确保状态被重置，避免死锁
                isGening = false;
                // 尝试处理下一个请求
                tryGenAudio();
            }
        } catch (Exception e) {
            log.error("音频生成队列处理异常: " + e.getMessage(), e);
            isGening = false;
            tryGenAudio(); // 尝试处理下一个
        }
    }


    private void fileTypeFolderAudioPlay(AudioGenDto audioGenDto) {
        ConfigDto configDto = audioGenDto.getConfigDto();
        BvScriptItem scriptItem = audioGenDto.getScriptItem();
        String[] lines = StringUtils.split(scriptItem.getScriptContent(), "\r\n");
        if (lines == null || lines.length == 0) {
            return;
        }

        boolean hasNonEmpty = Arrays.stream(lines).anyMatch(line -> line != null && !line.trim().isEmpty());
        if (!hasNonEmpty) {
            log.error("列表中没有非空元素");
            return;
        }

        // 检查主音频队列大小，避免过多添加
        Integer mainAudioQueueSize = audioPlayQueueService.getQueueSizeByScriptType(ScriptType.MAIN_AUDIO);
        if (mainAudioQueueSize >= MAX_MAIN_AUDIO_QUEUE_SIZE) {
            log.info("主音频队列已达到上限 {}，跳过添加此文件夹类型主音频任务", MAX_MAIN_AUDIO_QUEUE_SIZE);
            return;
        }

        //队列多大睡眠 - 这是主音频，需要等待
        bvAudioPlayService.fixQueneSizeSleep("mainAudio");

        Integer intervalMin = configDto.getMainAudioSetting().getIntervalMin();
        Integer intervalMax = configDto.getMainAudioSetting().getIntervalMax();
        Random random = new Random();
        int randomIndex = random.nextInt(lines.length);

        String scriptContent = lines[randomIndex];
        for (String line : lines) {
            int index = random.nextInt(lines.length);
            String tempLine = lines[index];

            if (StringUtils.isBlank(tempLine)) {
                continue;
            }
            tempLine = tempLine.trim();

            // 检查元素是否非空（去空格后判断）
            if (FileUtil.exist(tempLine)) {
                scriptContent = tempLine;
                break;
            }
        }
        if (StringUtils.isBlank(scriptContent)) {
            return;
        }

        // 去除开头的斜杠（适用于 Windows 文件系统）
        if (scriptContent.startsWith("/") && System.getProperty("os.name").contains("Windows")) {
            scriptContent = scriptContent.substring(1);
        }

        AudioPlayDto audioDto = new AudioPlayDto().setAudioFilePath(scriptContent)
                .setPlayScriptId(scriptItem.getId().toString())
                .setScriptType(ScriptType.MAIN_AUDIO)
                .setPlayLogPath(audioGenDto.getPlayLogPath())
                .setIntervalMin(intervalMin)
                .setIntervalMax(intervalMax)
                .setSpeed(MyDecimalUtil.getFloatSpeed(configDto.getAudioSetting().getPlay().getAnchor()))
                .setVolume(MyDecimalUtil.getFloatVolume(configDto.getAudioSetting().getVolume().getAnchor()));
        //正在播放的音频播放完成后插入到第一条
        audioPlayQueueService.addToQueue(audioDto, PlayerType.ANCHOR);
    }

    private void generateAudioAfterHandler(AudioGenDto audioGenDto, TextToSpeechVo result, PlayerType playerType) {

        if (result == null) {
            return;
        }
        ConfigDto configDto = audioGenDto.getConfigDto();
        PlayDto playDto = audioGenDto.getPlayDto();

        String audioFilePath = result.getAudioFilePath();
        if (StringUtils.isBlank(audioFilePath)) {
            return;
        }

        Boolean smartReplyOpen = false;
        Boolean smartQA = false;

        switch (playDto.getScriptType()) {
            case KEYWORD:
                smartReplyOpen = configDto.getKeywordSetting().getSmartReply().getOpen();
                break;
            case USER_ENTER:
                smartReplyOpen = configDto.getUserEnterSetting().getSmartReply().getOpen();
                break;
            default:
                break;
        }

        LambdaQueryWrapperExt<BvScriptItem> bvScriptItemQueryWrapper = new LambdaQueryWrapperExt<>();
        bvScriptItemQueryWrapper.eq(BvScriptItem::getScriptType, playDto.getScriptType().getCode());
        bvScriptItemQueryWrapper.eq(BvScriptItem::getDelFlag, DelFlag.OK.getCode());
        bvScriptItemQueryWrapper.eq(BvScriptItem::getScriptCategoryId, configDto.getFileDirectory().getCategoryId());
        List<BvScriptItem> list = bvScriptItemService.list(bvScriptItemQueryWrapper);
        Long scriptId = null;
        if (!CollectionUtils.isEmpty(list)) {
            scriptId = list.get(0).getId();
        }
//        PlayerType playerType = PlayerType.getPlayerTypeByCode(audioGenDto.getSpeaker());
        Integer volume = configDto.getAudioSetting().getVolume().getAnchor();
        ConfigDto.AudioPlayBaseSetting playSetting = configDto.getAudioSetting().getPlay().getAnchor();

        if (PlayerType.ASSISTANT.equals(playerType)) {
            volume = configDto.getAudioSetting().getVolume().getAssistant();
            playSetting = configDto.getAudioSetting().getPlay().getAssistant();
        }

        AudioPlayDto audioPlayDto = new AudioPlayDto().setAudioFilePath(audioFilePath)
                .setScriptType(playDto.getScriptType())
                .setText(result.getFinalText())
                .setOldText(result.getOldText())
                .setChannelId(configDto.getSseChannelId())
                .setPlayLogPath(audioGenDto.getPlayLogPath())
                .setIsSmartReply(smartReplyOpen || smartQA)
                .setPlayScriptId(scriptId == null ? "" : scriptId.toString())
                .setScriptCategoryId(configDto.getFileDirectory().getCategoryId())
                .setSpeed(MyDecimalUtil.getFloatSpeed(playSetting))
                .setVolume(MyDecimalUtil.getFloatVolume(volume))
                .setPlayerType(playerType);
        //正在播放的音频播放完成后插入到第一条
        log.error("生成一个generate音频加入到播放队列，音频路径：{},加入前队列大小：{}", audioFilePath, audioPlayQueueService.getQueueSize(PlayerType.ANCHOR));
        audioPlayQueueService.insertFirstToQueue(audioPlayDto, playerType);
    }

    private void mainAudioAfterHandler(AudioGenDto audioGenDto, TextToSpeechVo result, PlayerType playerType, boolean broadTime) {
        if (result == null) {
            return;
        }

        ConfigDto configDto = audioGenDto.getConfigDto();
        BvScriptItem scriptItem = audioGenDto.getScriptItem();

        Boolean smartReplyOpen = configDto.getMainAudioSetting().getSmartReply().getOpen();

        Integer intervalMin = configDto.getMainAudioSetting().getIntervalMin();
        Integer intervalMax = configDto.getMainAudioSetting().getIntervalMax();
        String audioFilePath = result.getAudioFilePath();
        if (StringUtils.isNotBlank(audioFilePath)) {
            AudioPlayDto audioPlayDto = new AudioPlayDto().setAudioFilePath(audioFilePath)
                    .setScriptType(ScriptType.MAIN_AUDIO)
                    .setText(result.getFinalText())
                    .setOldText(result.getOldText())
                    .setChannelId(configDto.getSseChannelId())
                    .setPlayScriptId(scriptItem.getId().toString())
                    .setScriptCategoryId(configDto.getFileDirectory().getCategoryId())
                    .setPlayFileName(scriptItem.getItemName())
                    .setPlayLogPath(audioGenDto.getPlayLogPath())
                    .setIsSmartReply(smartReplyOpen)
                    .setIntervalMax(intervalMax)
                    .setIntervalMin(intervalMin)
                    .setOldScriptContent(audioGenDto.getText())
                    .setOldTempPath(audioGenDto.getGenerateAudioPath())
                    .setSpeed(MyDecimalUtil.getFloatSpeed(configDto.getAudioSetting().getPlay().getAnchor()))
                    .setPlayerType(playerType)
                    .setFutureTime(result.getFutureTime())
                    .setBroadTime(broadTime);

            log.error("生成一个主音频加入到播放队列，音频路径：{},加入前队列大小：{}", audioFilePath, audioPlayQueueService.getQueueSize(PlayerType.ANCHOR));
            audioPlayQueueService.addToQueue(audioPlayDto, playerType);
        }
    }

    // 辅助方法：确定播放者类型
    private PlayerType determinePlayerType(String source, BvScriptItem scriptItem, ConfigDto configDto, PlayDto
            playDto) {
        if ("generate".equals(source)) {
            String speaker = getSpeaker(playDto, configDto);
            PlayerType playerType = PlayerType.getPlayerTypeByCode(speaker);
            return playerType;
        } else {
            return (scriptItem != null && scriptItem.getItemName().contains("小助理")) ?
                    PlayerType.ASSISTANT :
                    PlayerType.ANCHOR;
        }
    }


    // 辅助方法：确定目标模型名称
    private String determineModelName(PlayerType playerType, ConfigDto configDto) {
        return PlayerType.ANCHOR.equals(playerType) ?
                configDto.getModelSetting().getAnchor() :
                configDto.getModelSetting().getAssistant();
    }

    // 辅助方法：模型切换
//    private void switchModelIfNeeded(String targetModel, String currentModel) {
//        if (!targetModel.equals(currentModel)) {
//            log.info("Switching model from {} to {}", currentModel, targetModel);
//            bvModelService.switchModel(targetModel);
//        }
//    }

    /**
     * 获取音频的播放器发音人
     *
     * @param dto
     * @param configDto
     * @return
     */
    private static String getSpeaker(PlayDto dto, ConfigDto configDto) {

        String speaker = BvConstants.DEFAULT_SPEAKER;
        switch (dto.getScriptType()) {
            case INSERT_AUDIO:
                speaker = configDto.getInsertAudioSetting().getType();
                break;
            case KEYWORD:
                speaker = configDto.getKeywordSetting().getType();
                break;
            case USER_ENTER:
                speaker = configDto.getUserEnterSetting().getType();
                break;
            default:
                break;
        }
        return speaker;
    }

}
